use ftp::FtpError;
use ftp::{types::FileType, FtpStream};
use std::fs::File;
use std::io::Cursor;
use std::io::{self, BufReader, Read};
use std::path::{Path, PathBuf};
use std::str;

// https://cloud.tencent.com/developer/article/1677196
// cargo run --example ftptest
// 启动服务器
// D:\soft\apache-ftpserver-1.2.0\bin\startFtp.bat
//  port 2121  xue 123456
fn main() {
    println!("Hello rust-ftp!");
    // Create a connection to an FTP server and authenticate to it.
    let mut ftp_stream = FtpStream::connect("127.0.0.1:2121").unwrap();
    let _ = ftp_stream.login("xue", "123456").unwrap();

    // Get the current directory that the client will be reading from and writing to.
    println!("Current directory: {}", ftp_stream.pwd().unwrap());

    // Change into a new directory, relative to the one we are currently in.
    let _ = ftp_stream.cwd("/test_data").unwrap();

    // Retrieve (GET) a file from the FTP server in the current working directory.
    let remote_file = ftp_stream.simple_retr("a.txt").unwrap();
    println!(
        "Read file with contents\n{}\n",
        str::from_utf8(&remote_file.into_inner()).unwrap()
    );

    // 递归创建目录,注意目录必须以 /开始,且以 /分割
    let to_path = Path::new("/test_data1/aaa/bbbb/ccc");
    let mut current_path = PathBuf::new();
    let mut to_full_path_it = to_path.iter();
    while let Some(cpath) = to_full_path_it.next() {
        current_path.push(cpath);
        let current = current_path.to_str().unwrap();
        //println!("current: {}", current);
        if let Err(e) = ftp_stream.cwd(current) {
            match e {
                FtpError::InvalidResponse(msg) => {
                    // InvalidResponse("Expected code [250], got response: 550 No such directory.\r\n")
                    // println!("cwd {} , error: {}",current,msg);
                    if msg.contains("550 No such directory") {
                        // 创建子目录
                        ftp_stream.mkdir(current).unwrap();
                        // 切换到子目录
                        ftp_stream.cwd(current).unwrap();
                    }
                }
                _ => (),
            }
        }
    }

    // Store (PUT) a file from the client to the current working directory of the server.
    let mut reader = Cursor::new("Hello from the Rust \"ftp\" crate!".as_bytes());
    let _ = ftp_stream.put("hello-rustftp.txt", &mut reader);
    println!("Successfully upload hello-rustftp.txt");

    // Read and upload a.mp4 file

    let file_path =
        Path::new("E:/BaiduNetdiskDownload/01.高数基础/01新文道版本/31.第五章-定积分的应用.mp4");
    let file = File::open(file_path).unwrap();

    let file_size = file.metadata().unwrap().len();
    let reader = BufReader::new(file);

    let mut progress_reader = ProgressReader::new(reader, file_size);
    // Assuming ftp_stream is already defined and connected
    // 默认是文本模式 这里需要设置为2进制模式
    ftp_stream.transfer_type(FileType::Binary).unwrap();
    ftp_stream
        .put(
            file_path.file_name().unwrap().to_str().unwrap(),
            &mut progress_reader,
        )
        .unwrap();

    // Terminate the connection to the server.
    ftp_stream.quit().unwrap();
}

struct ProgressReader<R> {
    reader: R,
    total_size: u64,
    uploaded_size: u64,
}

impl<R: Read> ProgressReader<R> {
    fn new(reader: R, total_size: u64) -> Self {
        Self {
            reader,
            total_size,
            uploaded_size: 0,
        }
    }

    fn progress(&self) -> f64 {
        (self.uploaded_size as f64 / self.total_size as f64) * 100.0
    }
}

impl<R: Read> Read for ProgressReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let bytes_read = self.reader.read(buf)?;
        self.uploaded_size += bytes_read as u64;
        // Channels 设计为快速并提供有序数据。它们在内部用于流式处理操作，例如下载进度、子进程输出和 WebSocket 消息
        // https://tauri.app/develop/calling-frontend/#_top
        println!("Uploaded: {:.2}%", self.progress());
        Ok(bytes_read)
    }
}
